package nanzhuli.user.svc.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.io.ClassPathResource;

import java.io.IOException;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

/**
 * 描述：JsonUtil工具类
 * 作者： wephone   
 * 创建日期： 2018年3月16日 下午3:58:57
 * 版权：江泰保险经纪股份有限公司
 */
@Slf4j
public class JsonUtil {
	private static final ObjectMapper mapper = new ObjectMapper();
    static {
        mapper.setSerializationInclusion(Include.NON_NULL);
        //设置输入时忽略JSON字符串中存在而Java对象实际没有的属性
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }

    public static String object2Json(Object o) throws JsonProcessingException {
        if (o == null) {
        	  return null;
        }
        return  mapper.writeValueAsString(o);
    }

    public static <T> List<String> listObject2ListJson(List<T> objects) throws JsonProcessingException {
        if (objects == null) {
        	return null;
        }
        List<String> lists = new ArrayList<>();
        for (T t : objects) {
            lists.add(JsonUtil.object2Json(t));
        }
        return lists;
    }

    public static <T> List<T> listJson2ListObject(List<String> jsons, Class<T> c) throws IOException {
        if (jsons == null) {
        	 return null;
        }
        List<T> ts = new ArrayList<>();
        for (String j : jsons) {
            ts.add(JsonUtil.json2Object(j, c));
        }
        return ts;
    }
    public static <T> T json2Object(String json, Class<T> c) throws IOException {
        if (!StringUtils.isNotEmpty(json)) {
        	  return null;
        }
        return mapper.readValue(json, c);
    }

    public static <T> T json2Object(String json, TypeReference<T> tr) throws IOException {
        if (!StringUtils.isNotEmpty(json)) {
        	return null;
        }
        return mapper.readValue(json, tr);
    }
    /**
     * 
     * @return
     * 描述： 转json并忽略对象中的null
     */
    public static String Object2JsonLoseNull(Object o) throws JsonProcessingException {
        mapper.setSerializationInclusion(Include.NON_NULL);
        return mapper.writeValueAsString(o);
    }
    public static <T> Collection<T> fromJson(String json,Class<? extends Collection> collectionClazz,Class<T> clazz) throws IOException {
        if(json == null){
            return null;
        }
        return mapper.readValue(json, getCollectionType(collectionClazz,clazz));
    }
    private static JavaType getCollectionType(Class<?> collectionClass, Class<?>... elementClasses) {
		return mapper.getTypeFactory().constructParametricType(collectionClass, elementClasses);   
	}
    public static <T> T readJsonFromClassPath(String path, Type type) throws IOException {

        ClassPathResource resource = new ClassPathResource(path);
        if (resource.exists()) {
            return JSON.parseObject(resource.getInputStream(), StandardCharsets.UTF_8, type,
                    // 自动关闭流
                    Feature.AutoCloseSource,
                    // 允许注释
                    Feature.AllowComment,
                    // 允许单引号
                    Feature.AllowSingleQuotes,
                    // 使用 Big decimal
                    Feature.UseBigDecimal);
        } else {
            throw new IOException();
        }
    }

    /**
     * 通用的 通过json路径找到json值
     * @param jsonObject 要取值的json对象
     * @param path 对象路径
     * @return 对象值列表 由于可能存在A.B.C路径中B为列表的情况，所以结果可能有多个
     */
    public static List<Object> getJsonFieldValue(JSONObject jsonObject, String path) {
        List<String> keyWordList = new ArrayList(Arrays.asList(path.split("\\.")));
        List<Object> list = new ArrayList<>();
        String key = keyWordList.get(0);
        Object object = jsonObject.get(key);
        keyWordList.remove(0);
        if (keyWordList.isEmpty()) {
            if (null != object) {
                list.add(object);
            }
            return list;
        }

        String subPath = StringUtils.join(keyWordList, ".");
        if (object instanceof JSONArray) {
            JSONArray jsonArray = JSONArray.parseArray(JSON.toJSONString(object));
            if (jsonArray.isEmpty()) {
                return new ArrayList<>();
            }
            jsonArray.forEach(e -> list.addAll(getJsonFieldValue(JSON.parseObject(JSON.toJSONString(e)), subPath)));
        }else if(object instanceof JSONObject){
            JSONObject subJsonObject = JSONObject.parseObject(JSON.toJSONString(object));
            list.addAll(getJsonFieldValue(JSON.parseObject(JSON.toJSONString(subJsonObject)), subPath));
        }
        return list;
    }

    /**
     * 通用的 通过json路径找到json值
     * @param jsonObject 要取值的json对象
     * @param path 对象路径
     * @param value 要设置的值
     * @return 修改后的对象
     */
    public static Object setJsonFieldValue(JSONObject jsonObject, String path, Object value) {
        List<String> keyWordList = new ArrayList(Arrays.asList(path.split("\\.")));
        String key = keyWordList.get(0);
        keyWordList.remove(0);
        //如果关键词为空，说明此处为目标点，设置值
        if (keyWordList.isEmpty()) {
            jsonObject.fluentPut(key,value);
            return jsonObject;
        }
        //关键词不为空，取出子jsonObject进行递归
        Object object = jsonObject.get(key);

        String subPath = StringUtils.join(keyWordList, ".");
        if (object instanceof JSONArray) {
            JSONArray jsonArray = JSONArray.parseArray(JSON.toJSONString(object));
            if (jsonArray.isEmpty()) {
                //说明不是目标点,原样返回
                return object;
            }
            JSONArray newArray = new JSONArray();
            jsonArray.forEach(e -> newArray.add(setJsonFieldValue(JSON.parseObject(JSON.toJSONString(e)), subPath,value)));
            jsonObject.fluentPut(key,newArray);
        }else if(object instanceof JSONObject){
            JSONObject subJsonObject = JSONObject.parseObject(JSON.toJSONString(object));
            jsonObject.fluentPut(key,setJsonFieldValue(JSON.parseObject(JSON.toJSONString(subJsonObject)), subPath,value));
        }
        return jsonObject;
    }
    
}
